#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <cstdbool>
#include <algorithm>
#include <unistd.h>
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Conditional.hpp"

namespace YX
{
    const int g_default_size = 9;
    const size_t g_output = 3;
}

// 单例---懒汉模式
template <class T>
class ThreadPool
{
private:
    int _threadSize;          // 线程数量
    std::queue<T> *_proQueue; // 消费队列
    std::queue<T> *_conQueue; // 生产队列
    std::queue<T> _queueX;
    std::queue<T> _queueY;
    std::vector<Thread *> _threads; // 线程指针数组

    Mutex _proMutex;
    Mutex _conMutex;

    Conditional _cond;

    // 将构造私有,拷贝构造与赋值重载delete (注意构造不能delete可以default)
    ThreadPool(int size = YX::g_default_size)
        : _threadSize(size), _proQueue(nullptr), _conQueue(nullptr), _threads(size, nullptr)
    {
        _proQueue = &_queueX;
        _conQueue = &_queueY;
        for (int i = 0; i < size; i++)
        {
            _threads[i] = new Thread(i + 1, &ThreadStack, (void *)this);
        }
    }

    ThreadPool(const ThreadPool<T> &other) = delete;

    ThreadPool<T> &operator=(const ThreadPool<T> &other) = delete;

    // 因为是懒汉模式,所以这里必须为对象指针
    static ThreadPool<T> *_threadPoolPtr;

    // 静态互斥锁
    static pthread_mutex_t _mutex;

public:
    // 访问静态成员变量的函数需要为静态成员函数
    static ThreadPool<T> *GetInstance(int size = YX::g_default_size)
    {
        // 避免大量的线程在_threadPoolPtr不为空时,仍然进行大量的加锁与解锁操作
        if (nullptr == _threadPoolPtr)
        {
            // _threadPoolPtr为临界资源,所以必须要保证原子性访问
            pthread_mutex_lock(&_mutex);
            if (nullptr == _threadPoolPtr)
            {
                _threadPoolPtr = new ThreadPool<T>(size);
            }
            pthread_mutex_unlock(&_mutex);
        }

        return _threadPoolPtr;
    }

    ~ThreadPool()
    {
        // 保证没有线程在工作...
        _proMutex.Lock();
        for (auto &iter : _threads)
        {
            iter->Cancel();
            iter->Join();
            delete iter;
        }
        _proMutex.UnLock();

        // 将所有任务完成

        while (!_proQueue->empty())
        {
            T task;
            task = _proQueue->front();
            task = _proQueue->pop();
            task(std::string("主线程"));
        }
    }

    void Run()
    {
        for (auto &iter : _threads)
        {
            iter->Create();
            std::cout << iter->GetName() << "启动成功" << std::endl;
        }
    }

    static void *ThreadStack(void *args)
    {
        ThreadData *ptd = (ThreadData *)args;
        ThreadPool<T> *ptp = (ThreadPool<T> *)ptd->_objThis;

        T task;
        while (true)
        {
            ptp->_proMutex.Lock();
            // 先判断消费队列是否满足条件
            while (ptp->_proQueue->empty())
            {
                ptp->_cond.Wait(ptp->_proMutex);
            }
            task = ptp->_proQueue->front();
            ptp->_proQueue->pop();
            ptp->_proMutex.UnLock();

            // 消费
            task(ptd->_name);
            sleep(1);
        }
    }

    void PushTask(const T &task)
    {
        // 进行生产
        _conMutex.Lock();
        _conQueue->push(task);

        // 只有生产队列中的任务到达一定数量才能开始消费
        if (_conQueue->size() >= (size_t)YX::g_output)
        {
            // 确保没有消费者在进行获取消费
            _proMutex.Lock();
            std::swap(_proQueue, _conQueue);
            _proMutex.UnLock();
            _cond.BroadCast();
        }

        _conMutex.UnLock();
    }
};
template <class T>
ThreadPool<T> *ThreadPool<T>::_threadPoolPtr = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::_mutex = PTHREAD_MUTEX_INITIALIZER;

// // 单例---饿汉模式
// template<class T>
// class ThreadPool
// {
// private:
//     int _size; // 线程数量
//     std::vector<Thread *> _threads; // 线程数组
//     std::queue<T> _taskQueue; // 任务队列
//     Mutex _mutex; // 任务队列的互斥锁
//     Conditional _cond; // 消费者的条件变量

//     ThreadPool(int size=YX::g_default_size):_size(size),_threads(size,nullptr)
//     {
//         for(int i=0;i<size;++i)
//         {
//             _threads[i]=new Thread(i+1,routine,(void*)this);
//         }
//     }

//     ThreadPool(const ThreadPool<T> &t)=delete;
//     ThreadPool<T> &operator=(const ThreadPool<T> &t)=delete;

//     static ThreadPool<T> _threadPoolObj;

//     //static pthread_mutex_t _threadPoolMutex;

// public:
//     static Mutex _threadPoolMutex;

//     static ThreadPool<T> *GetInstance(int size=YX::g_default_size)
//     {
//         return &_threadPoolObj;
//     }

//     void Run()
//     {
//         // 将池中的线程"运行"起来
//         for(auto &iter : _threads)
//         {
//             iter->Create();
//             std::cout<<iter->GetName()<<"启动成功"<<std::endl;
//         }
//     }

//     static void *routine(void *args)
//     {
//         ThreadData *ptd=(ThreadData *)args; // ThreadData指针

//         ThreadPool<T> *ptp=(ThreadPool<T> *)ptd->_objThis; // 线程池对应的this指针

//         while(true)
//         {

//             // std::cout<<"queue size:"<<ptp->_taskQueue.size()<<std::endl; // 可以直接通过this指针访问

//             // 获取任务
//             ptp->_mutex.Lock();
//             while(ptp->_taskQueue.empty())
//             {
//                 ptp->_cond.Wait(ptp->_mutex);
//             }
//             T task = ptp->_taskQueue.front();
//             ptp->_taskQueue.pop();
//             ptp->_mutex.UnLock();

//             // 消费任务
//             task(ptd->_name);
//             sleep(2);
//         }
//     }

//     void PushTask(const T& task)
//     {
//         // 生产任务
//         _mutex.Lock();
//         _taskQueue.push(task);
//         _mutex.UnLock();
//         _cond.Signal();
//         //_cond.BroadCast();
//     }

//     ~ThreadPool()
//     {
//         // _mutex.Lock();
//         for(auto &iter : _threads)
//         {
//             iter->Cancel();
//             iter->Join();
//             delete iter;
//         }
//         // _mutex.UnLock();
//     }
// };
// // 静态成员的定义
// template<class T>
// ThreadPool<T> ThreadPool<T>::_threadPoolObj;

// // template<class T>
// // pthread_mutex_t ThreadPool<T>::_threadPoolMutex=PTHREAD_MUTEX_INITIALIZER;
// template<class T>
// Mutex ThreadPool<T>::_threadPoolMutex;